
module sn76489_noise(
  input  wire       clock_i,
  input  wire       clk_en_i,
  input  wire       res_n_i,
  input  wire       we_i,
  input  wire [7:0] d_i,
  input  wire       r2_i,
  input  wire       tone3_ff_i,
  output wire [7:0] noise_o  
);

//CPU Registers
reg [1:0] nf_q; //Select shift rate
reg       fb_q; //Select the mode 0-periodic 1-white 
reg [3:0] a_q;
always @(posedge clock_i or negedge res_n_i)begin
    if(!res_n_i)begin
	nf_q <= #1 2'b0;
	fb_q <= #1 1'b0;
    end	
    else if(!clk_en_i)begin
	nf_q <= #1 nf_q;
	fb_q <= #1 fb_q;
    end
    else if(we_i && !r2_i)begin
	nf_q <= #1 d_i[1:0];
	fb_q <= #1 d_i[2];
    end
end

always @(posedge clock_i or negedge res_n_i)begin
    if(!res_n_i)
	a_q <= #1 4'hf;
    else if(!clk_en_i)
	a_q <= #1 a_q;
    else if(we_i && r2_i)
	a_q <= #1 d_i[3:0];
end

//--Freq generation
reg [6:0] freq_cnt_q;
reg       freq_ff_q;
always @(posedge clock_i or negedge res_n_i)begin
    if(!res_n_i)
	freq_cnt_q <= #1 7'b0;
    else if(!clk_en_i)
	freq_cnt_q <= #1 freq_cnt_q;
    else if(freq_cnt_q==7'b0)
	case(nf_q)
        2'b00: freq_cnt_q <= #1 7'd31;
        2'b01: freq_cnt_q <= #1 7'd63;
        2'b10: freq_cnt_q <= #1 7'd127;
        2'b11: freq_cnt_q <= #1 7'd0;  //Used Channel 2 tone counter
	endcase
    else 
        freq_cnt_q <= #1 freq_cnt_q - 1'b1;	    
end

always @(posedge clock_i or negedge res_n_i)begin
    if(!res_n_i)
	freq_ff_q <= #1 1'b0;
    else if(!clk_en_i)
	freq_ff_q <= #1 freq_ff_q;
    else if(freq_cnt_q==7'b0)
        freq_ff_q <= #1 ~freq_ff_q;
end

wire shift_source_s = (nf_q==2'b11) ? tone3_ff_i : freq_ff_q;
reg  shift_source_q;
always @(posedge clock_i or negedge res_n_i)begin
    if(!res_n_i)
	shift_source_q <= #1 1'b0;
    else if(clk_en_i)
	shift_source_q <= #1 shift_source_s; 
end

wire shift_rist_edge_s = shift_source_s & (~shift_source_q);

reg [15:0] lfsr_q;
always @(posedge clock_i or negedge res_n_i)begin
    if(!res_n_i)
	 lfsr_q <= #1 16'h8000;
    else if(!clk_en_i)
	 lfsr_q <= #1 lfsr_q;
    else if(we_i && !r2_i)
	 lfsr_q <= #1 16'h8000;
    else if(shift_rist_edge_s)
	 if(!fb_q)
	     lfsr_q <= #1 {lfsr_q[0], lfsr_q[15:1]};
	 else
	     lfsr_q <= #1 {lfsr_q[0]^lfsr_q[3], lfsr_q[15:1]};
end

wire [1:0] freq_s = lfsr_q[0] ? 2'b01 : 2'b00;

sn76489_attenuator U_sn76489_attenuator(
    .attenuation_i  ( a_q     ) ,
    .factor_i       ( freq_s  ) ,
    .product_o      ( noise_o )
);

endmodule
